package com.frejoys.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.frejoys.common.dto.admin.StoreActivityQueueListDto;
import com.frejoys.common.dto.admin.StoreIdAndPageDto;
import com.frejoys.common.dto.admin.StoreIdAndStoreActivityIdDto;
import com.frejoys.common.dto.common.IdDto;
import com.frejoys.common.enums.*;
import com.frejoys.common.error.HttpStatus;
import com.frejoys.common.exception.GeneralException;
import com.frejoys.common.util.AppConfigUtil;
import com.frejoys.common.util.CommonUtil;
import com.frejoys.common.vo.admin.StoreActivityQueueListVo;
import com.frejoys.common.vo.store.StoreActivityQueueInfoVo;
import com.frejoys.common.vo.store.StoreActivityQueueVo;
import com.frejoys.dao.entity.*;
import com.frejoys.dao.mapper.StoreActivityMapper;
import com.frejoys.dao.mapper.StoreActivityQueueMapper;
import com.frejoys.dao.mapper.StoreMapper;
import com.frejoys.dao.mapper.UserMapper;
import com.frejoys.service.OrderService;
import com.frejoys.service.StoreActivityQueueService;
import com.frejoys.service.UserWalletLogService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

// 店家
@Service
@RequiredArgsConstructor
public class StoreActivityQueueServiceImpl extends ServiceImpl<StoreActivityQueueMapper, StoreActivityQueue> implements StoreActivityQueueService {

    private final StoreActivityMapper storeActivityMapper;

    private final StoreMapper storeMapper;

    private final UserMapper userMapper;

    private final UserWalletLogService userWalletLogService;

    private final OrderService orderService;

    @Override
    public StoreActivityQueue getFirstSimpleInfo(Integer storeActivityId, Integer status) {
        LambdaQueryWrapper<StoreActivityQueue> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreActivityQueue::getStoreActivityId, storeActivityId).eq(StoreActivityQueue::getStatus, status);
        return getOnly(wrapper);
    }

    @Override
    public boolean delInfo(Integer id) {
        LambdaUpdateWrapper<StoreActivityQueue> adUpdateWrapper = new LambdaUpdateWrapper<>();
        adUpdateWrapper.set(StoreActivityQueue::getStatus, EStatus.off.getValue());
        adUpdateWrapper.eq(StoreActivityQueue::getId, id);
        return update(adUpdateWrapper);
    }

    @Override
    public StoreActivityQueueInfoVo getInfo(IdDto dto) {
        LambdaQueryWrapper<StoreActivityQueue> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(StoreActivityQueue::getId, StoreActivityQueue::getStoreActivityId, StoreActivityQueue::getPrice,
                StoreActivityQueue::getType, StoreActivityQueue::getStatus, StoreActivityQueue::getCreateTime).eq(StoreActivityQueue::getId, dto.getId());
        StoreActivityQueue activityQueue = getOnly(queryWrapper);
        StoreActivityQueueInfoVo queueInfoVo = new StoreActivityQueueInfoVo();
        if (activityQueue != null && activityQueue.getStoreActivityId() != null) {
            StoreActivity storeActivity = storeActivityMapper.selectById(activityQueue.getStoreActivityId());
            Store store = storeMapper.getSimpleInfo(storeActivity.getStoreId());
            queueInfoVo = BeanUtil.copyProperties(storeActivity, StoreActivityQueueInfoVo.class);
            BeanUtil.copyProperties(storeActivity, queueInfoVo);
            queueInfoVo.setStoreName(store.getName());
            queueInfoVo.setLogo(AppConfigUtil.getUrlPrefix(store.getLogo(), EFileSize.logo.getValue()));
            return queueInfoVo;
        }
        return queueInfoVo;
    }

    @Override
    public List<StoreActivityQueueVo> listInfo(StoreActivityQueueListDto dto, Long userId) {
        Page<StoreActivityQueue> page = new Page<>(dto.getPage(), dto.getSize());
        page.setSearchCount(false);

        LambdaQueryWrapper<StoreActivityQueue> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(StoreActivityQueue::getId, StoreActivityQueue::getStoreActivityId, StoreActivityQueue::getPrice,
                StoreActivityQueue::getType, StoreActivityQueue::getStatus,
                StoreActivityQueue::getCreateTime).eq(StoreActivityQueue::getUserId, userId);

        List<StoreActivityQueue> list = baseMapper.selectPage(page, queryWrapper).getRecords();
        List<StoreActivityQueueVo> storeActivityQueueVos = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(list)) {
            storeActivityQueueVos = BeanUtil.copyToList(list, StoreActivityQueueVo.class);
            List<Integer> activityIds = list.stream().map(StoreActivityQueue::getStoreActivityId).toList();

            //获取排队位置
            LambdaQueryWrapper<StoreActivityQueue> aWrapper = new LambdaQueryWrapper<>();
            aWrapper.select(StoreActivityQueue::getId,StoreActivityQueue::getStoreActivityId)
                    .in(StoreActivityQueue::getStoreActivityId,activityIds)
                    .eq(StoreActivityQueue::getStatus, EStoreActivityQueueStatus.wait.getValue())
                    .orderByAsc(StoreActivityQueue::getCreateTime);
            List<StoreActivityQueue> storeActivityQueues = baseMapper.selectList(aWrapper);
            Map<Integer, List<StoreActivityQueue>> storeActivityQueueMap = storeActivityQueues.stream().collect(Collectors.groupingBy(StoreActivityQueue::getStoreActivityId));

            LambdaQueryWrapper<StoreActivity> wrapper = Wrappers.lambdaQuery();
            wrapper.select(StoreActivity::getId, StoreActivity::getStoreId, StoreActivity::getTotalMoney,StoreActivity::getMoney)
                    .in(StoreActivity::getId, activityIds);
            List<StoreActivity> storeActivities = storeActivityMapper.selectList(wrapper);

            Map<Integer, BigDecimal> map = storeActivities.stream().collect(Collectors.toMap(StoreActivity::getId, StoreActivity::getTotalMoney));
            Map<Integer, BigDecimal> moneyMap = storeActivities.stream().collect(Collectors.toMap(StoreActivity::getId, StoreActivity::getMoney));

            List<Store> storeList = storeMapper.getStoreListByActivityId(activityIds);

            Map<Integer, Store> storeMap = storeList.stream().collect(Collectors.toMap(Store::getId, store -> store));

            for (StoreActivityQueueVo v : storeActivityQueueVos) {
                if (map.containsKey(v.getStoreActivityId())) {
                    v.setTotalMoney(map.get(v.getStoreActivityId()));
                }
                if (storeMap.containsKey(v.getStoreActivityId())) {
                    v.setStoreName(storeMap.get(v.getStoreActivityId()).getName());
                    v.setLogo(AppConfigUtil.getUrlPrefix(storeMap.get(v.getStoreActivityId()).getLogo(), EFileSize.logo.getValue()));
                }

                Integer nowSort = 0;
                if (v.getStatus() == EStoreActivityQueueStatus.wait.getValue()){
                    if (storeActivityQueueMap.containsKey(v.getStoreActivityId())){
                        List<StoreActivityQueue> activityQueues = storeActivityQueueMap.get(v.getStoreActivityId());
                        List<Integer> idList = activityQueues.stream().map(StoreActivityQueue::getId).toList();

                        if (idList.contains(v.getId())) {
                            nowSort = idList.indexOf(v.getId())+1;
                        }
                    }
                }

                v.setNowSort(nowSort);
                if (v.getNowSort() == 1){
                    v.setMoney(moneyMap.get(v.getStoreActivityId()));
                }
            }
        }

        return storeActivityQueueVos;
    }

    @Override
    public List<StoreActivityQueueVo> adminListInfo(StoreActivityQueueListDto dto) {
        Page<StoreActivityQueue> page = new Page<>(dto.getPage(), dto.getSize());

        LambdaQueryWrapper<StoreActivityQueue> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(StoreActivityQueue::getId, StoreActivityQueue::getStoreActivityId, StoreActivityQueue::getPrice,
                StoreActivityQueue::getRebateMoney, StoreActivityQueue::getType, StoreActivityQueue::getStatus,
                StoreActivityQueue::getCreateTime);

        List<StoreActivityQueue> list = baseMapper.selectPage(page, queryWrapper).getRecords();
        List<StoreActivityQueueVo> storeActivityQueueVos = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(list)) {
            storeActivityQueueVos = BeanUtil.copyToList(list, StoreActivityQueueVo.class);
            List<Integer> activityIds = list.stream().map(StoreActivityQueue::getStoreActivityId).toList();
            LambdaQueryWrapper<StoreActivity> wrapper = Wrappers.lambdaQuery();
            wrapper.select(StoreActivity::getId, StoreActivity::getStoreId, StoreActivity::getTotalMoney).in(StoreActivity::getId, activityIds);
            List<StoreActivity> storeActivities = storeActivityMapper.selectList(wrapper);

            Map<Integer, BigDecimal> map = storeActivities.stream().collect(Collectors.toMap(StoreActivity::getId, StoreActivity::getTotalMoney));

            List<Store> storeList = storeMapper.getStoreListByActivityId(activityIds);

            Map<Integer, Store> storeMap = storeList.stream().collect(Collectors.toMap(Store::getId, store -> store));

            for (StoreActivityQueueVo v : storeActivityQueueVos) {
                v.setTotalMoney(map.get(v.getStoreActivityId()));
                v.setStoreName(storeMap.get(v.getStoreActivityId()).getName());
                v.setLogo(AppConfigUtil.getUrlPrefix(storeMap.get(v.getStoreActivityId()).getLogo(), EFileSize.logo.getValue()));
                v.setRebateMoney(CommonUtil.bigDecimalSubtract(v.getPrice(), v.getRebateMoney()));
            }
        }

        return storeActivityQueueVos;
    }


    @Override
    public IPage<StoreActivityQueueListVo> activityQueueListInfo(StoreIdAndStoreActivityIdDto dto) {
        Page page = new Page<>(dto.getPage(), dto.getSize());

        List<Integer> ids = new ArrayList<>();
        Long userId = null;

       if (dto.getStoreId() != null){
           LambdaQueryWrapper<StoreActivity> queryWrapper = new LambdaQueryWrapper<>();
           queryWrapper.select(StoreActivity::getId)
                   .eq(StoreActivity::getStoreId,dto.getStoreId());
           List<StoreActivity> storeActivityList = storeActivityMapper.selectList(queryWrapper);
           ids = storeActivityList.stream().map(StoreActivity::getId).toList();
       }

        List<Integer> storeActivityIdList = new ArrayList<>();
       if (StrUtil.isNotEmpty(dto.getPhone())){
           userId = userMapper.phoneByUserId(dto.getPhone());
       }
        if (StrUtil.isNotEmpty(dto.getName())){
            List<Store> storeNameById = storeMapper.getStoreNameById(dto.getName());
            List<Integer> storeIdList = storeNameById.stream().map(Store::getId).toList();
            if (storeIdList.isEmpty()){
                return new Page<>();
            }
            LambdaQueryWrapper<StoreActivity> storeActivityWrapper = new LambdaQueryWrapper<>();
            storeActivityWrapper.select(StoreActivity::getId).in(StoreActivity::getStoreId,storeIdList);
            List<StoreActivity> storeActivityList = storeActivityMapper.selectList(storeActivityWrapper);
            storeActivityIdList = storeActivityList.stream().map(StoreActivity::getId).toList();
        }

        //查询活动队列
        IPage<StoreActivityQueueListVo> listVoIPage = baseMapper.activityQueueListInfo(page,ids,dto,userId,storeActivityIdList);

        List<StoreActivityQueueListVo> listVos = listVoIPage.getRecords();

        if (!listVos.isEmpty()){

            List<Integer> storeActivityIds = listVos.stream().map(StoreActivityQueueListVo::getStoreActivityId).distinct().toList();

            //查询活动
            LambdaQueryWrapper<StoreActivity> storeActivityWrapper = new LambdaQueryWrapper<>();
            storeActivityWrapper.select(StoreActivity::getStoreId,StoreActivity::getId);

            if (!storeActivityIds.isEmpty()){
                storeActivityWrapper.in(StoreActivity::getId,storeActivityIds);
            }
            List<StoreActivity> storeActivityList = storeActivityMapper.selectList(storeActivityWrapper);

            Map<Integer, Integer> storeIdMap = storeActivityList.stream().collect(Collectors.toMap(StoreActivity::getId, StoreActivity::getStoreId));
            List<Integer> storeIds = storeActivityList.stream().map(StoreActivity::getStoreId).distinct().toList();

            //查询店铺
            LambdaQueryWrapper<Store> storeWrapper = new LambdaQueryWrapper<>();
            storeWrapper.select(Store::getId,Store::getName,Store::getLogo);

            if (!storeIds.isEmpty()){
                storeWrapper.in(Store::getId,storeIds);
            }
            List<Store> storeList = storeMapper.selectList(storeWrapper);
            Map<Integer, Store> storeMap = storeList.stream().collect(Collectors.toMap(Store::getId, store -> store));

            //查询用户信息
            List<Long> userIds = listVos.stream().map(StoreActivityQueueListVo::getUserId).toList();
            List<User> users = userMapper.getUserByIds(userIds);
            Map<Long, User> userMap = users.stream().collect(Collectors.toMap(User::getId, user -> user));

            //获取排队位置
            LambdaQueryWrapper<StoreActivityQueue> aWrapper = new LambdaQueryWrapper<>();
            aWrapper.select(StoreActivityQueue::getStoreActivityId,StoreActivityQueue::getOrderSn)
                    .in(StoreActivityQueue::getStoreActivityId,storeActivityIds)
                    .eq(StoreActivityQueue::getStatus, EStoreActivityQueueStatus.wait.getValue())
                    .orderByAsc(StoreActivityQueue::getCreateTime);
            List<StoreActivityQueue> storeActivityQueues = baseMapper.selectList(aWrapper);
            Map<Integer, List<StoreActivityQueue>> storeActivityQueueMap = storeActivityQueues.stream().collect(Collectors.groupingBy(StoreActivityQueue::getStoreActivityId));

            for (StoreActivityQueueListVo vo:listVos){

                //插入排队信息
                Integer nowSort = 0;
                if (vo.getStatus() == EStoreActivityQueueStatus.wait.getValue()){
                    if (storeActivityQueueMap.containsKey(vo.getStoreActivityId())){
                        List<StoreActivityQueue> activityQueues = storeActivityQueueMap.get(vo.getStoreActivityId());
                        List<Long> idList = activityQueues.stream().map(StoreActivityQueue::getOrderSn).toList();

                        if (idList.contains(vo.getOrderSn())) {
                            nowSort = idList.indexOf(vo.getOrderSn())+1;
                        }
                    }
                }

                vo.setNowSort(nowSort);

                if (storeIdMap.containsKey(vo.getStoreActivityId())){
                    Store store = storeMap.get(storeIdMap.get(vo.getStoreActivityId()));
                    if (store != null){
                        vo.setStoreName(store.getName());
                        vo.setLogo(AppConfigUtil.getUrlPrefix(store.getLogo(),EFileSize.logo.getValue()));
                    }
                }
                if (userMap.containsKey(vo.getUserId())){
                    User user = userMap.get(vo.getUserId());
                    vo.setNickname(user.getNickname());
                    vo.setPhone(user.getPhone());
                }
            }
        }
        return listVoIPage;
    }

    @Override
    public StoreActivityQueue getStoreActivityQueueInfo(Long orderSn) {
        LambdaQueryWrapper<StoreActivityQueue> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreActivityQueue::getOrderSn,orderSn);
        return getOnly(wrapper);
    }


    @Override
    public boolean verifyActivityQueue(StoreActivityQueue storeActivityQueue) {

        if (storeActivityQueue == null){
            throw new GeneralException(HttpStatus.activityQueueNonentity);
        }

        //已转积分
        if (storeActivityQueue.getStatus() == EStoreActivityQueueStatus.score.getValue()){
            throw new GeneralException(HttpStatus.orderIsScore);
        }

        //已返利
        if (storeActivityQueue.getStatus() == EStoreActivityQueueStatus.rebate.getValue()){
            throw new GeneralException(HttpStatus.orderVerifyExistError);
        }

        return storeActivityQueue.getStatus() == EStoreActivityQueueStatus.wait.getValue();
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean finishOrderRebate(Long orderSn, Long userId) {

        //更新订单状态
        if (!orderService.updateOrderStatus(orderSn,userId, EVerify.finish.getValue(),EIsScore.wait.getValue())){
            throw new GeneralException(HttpStatus.deleteWalletLogError);
        }

        //删除钱包日志
        if (!userWalletLogService.deleteWalletLog(orderSn,userId, EUserWalletLogType.order.getValue())){
            throw new GeneralException(HttpStatus.deleteWalletLogError);
        }

        //更新队列状态
        LambdaUpdateWrapper<StoreActivityQueue> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(StoreActivityQueue::getOrderSn,orderSn)
                .eq(StoreActivityQueue::getUserId,userId)
                .eq(StoreActivityQueue::getStatus,EStoreActivityQueueStatus.wait.getValue())
                .set(StoreActivityQueue::getStatus,EStoreActivityQueueStatus.del.getValue());
        return update(wrapper);
    }


}